package com.dycx.cms.service.impl;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dycx.cms.converter.ArticleConverter;
import com.dycx.cms.dto.ArticleContentDTO;
import com.dycx.cms.dto.ArticleDTO;
import com.dycx.cms.dto.ArticleKeywordDTO;
import com.dycx.cms.entity.ArticleDO;
import com.dycx.cms.entity.ArticleTypeDO;
import com.dycx.cms.mapper.ArticleMapper;
import com.dycx.cms.service.ArticleContentService;
import com.dycx.cms.service.ArticleKeywordService;
import com.dycx.cms.service.ArticleService;
import com.dycx.cms.service.ArticleTypeService;
import com.dycx.cms.vo.ArticleContentVO;
import com.dycx.cms.vo.ArticleVO;
import com.dycx.common.dto.VideoInfoDTO;
import com.dycx.common.enums.BizTypeEnum;
import com.dycx.system.service.ConfigService;
import com.dycx.system.service.OssFileService;
import com.dycx.user.entity.CollectDO;
import com.dycx.user.enums.VipTypeEnum;
import com.dycx.user.service.CollectService;
import com.dycx.user.service.UserService;
import com.dycx.user.vo.UserVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class ArticleImpl extends ServiceImpl<ArticleMapper, ArticleDO> implements ArticleService {

    private final OssFileService ossFileService;
    private final ArticleKeywordService articleKeywordService;
    private final ArticleContentService articleContentService;
    private final ArticleTypeService articleTypeService;
    private final CollectService collectService;

    /**
     * 分页
     *
     * @return
     */
    @Override
    public Page<ArticleVO> getPage(ArticleDTO dto) {
        LambdaQueryWrapper<ArticleDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotBlank(dto.getTitle()), ArticleDO::getTitle, dto.getTitle());
        wrapper.like(StrUtil.isNotBlank(dto.getSummary()), ArticleDO::getSummary, dto.getSummary());
        wrapper.eq(ObjectUtil.isNotNull(dto.getArticleTypeId()), ArticleDO::getArticleTypeId, dto.getArticleTypeId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getStatus()), ArticleDO::getStatus, dto.getStatus());
        wrapper.in(ObjectUtil.isNotNull(dto.getParentId()), ArticleDO::getArticleTypeId,
                articleTypeService.toIntList(articleTypeService.getAllList(dto.getParentId(), true)));
        wrapper.in(ObjectUtil.isNotNull(dto.getIds()), ArticleDO::getId, dto.getIds());
        if (StrUtil.isBlank(dto.getOrderBy())) {
            wrapper.orderByDesc(ArticleDO::getId);
        } else {
            wrapper.last(" order by " + dto.getOrderBy());
        }

        Page<ArticleDO> entityPage = page(new Page<>(dto.getPageIndex(), dto.getPageSize()), wrapper);
        Page<ArticleVO> voPage = ArticleConverter.entityToVoPage(entityPage);
        voPage.setRecords(setListData(voPage.getRecords(), dto));
        return voPage;
    }

    @Override
    public List<ArticleVO> setListData(List<ArticleVO> articleList, ArticleDTO dto) {
        if (ObjectUtil.isEmpty(articleList)) return articleList;
        List<Integer> ids = articleList.stream()
                .map(ArticleVO::getArticleTypeId)
                .collect(Collectors.toList());
        LambdaQueryWrapper<ArticleTypeDO> typeWrapper = new LambdaQueryWrapper<>();
        typeWrapper.in(ArticleTypeDO::getId, ids);
        List<ArticleTypeDO> typeList = articleTypeService.list(typeWrapper);
        articleList.forEach(item -> {
            typeList.forEach(type -> {
                if (item.getArticleTypeId().equals(type.getId())) {
                    item.setArticleTypeName(type.getArticleTypeName());
                }
            });
        });

        return articleList;
    }

    /**
     * 查询详细
     *
     * @param id
     * @return
     */
    @Override
    public ArticleVO getDetailById(int id, Boolean status) {
        LambdaQueryWrapper<ArticleDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ArticleDO::getId, id);
        wrapper.eq(ObjectUtil.isNotEmpty(status), ArticleDO::getStatus, status);

        //文章内容
        ArticleDO articleDO = getOne(wrapper);
        Assert.notNull(articleDO, "未查询到内容");
        ArticleVO articleVO = ArticleConverter.entityToVo(articleDO);

        //查询类型
        ArticleContentVO articleContentVO = articleContentService.getInfo(id);
        articleVO.setContent(articleContentVO.getContent());

        //查询关键字
        ArticleKeywordDTO articleKeywordDto = new ArticleKeywordDTO();
        articleKeywordDto.setPageIndex(1);
        articleKeywordDto.setPageSize(100);
        articleKeywordDto.setArticleId(articleVO.getId());
        articleVO.setKeywordList(articleKeywordService.getPage(articleKeywordDto).getRecords());

        articleVO.setArticleTypeIdLevel(articleTypeService.getArticleTypeIdLevel(articleVO.getArticleTypeId()));

        return articleVO;
    }

    /**
     * 添加
     *
     * @param articleDto
     * @return
     */
    @Override
    public Boolean add(ArticleDTO articleDto) {
        ArticleDO articleEntity = ArticleConverter.dtoToEntity(articleDto);
        articleEntity.setHits((int) (Math.random() * 100));
        if (!this.save(articleEntity)) return false;

        ArticleContentDTO articleContentDTO = new ArticleContentDTO();
        articleContentDTO.setArticleId(articleEntity.getId());
        articleContentDTO.setContent(articleDto.getContent());
        if (!articleContentService.add(articleContentDTO)) throw new RuntimeException("添加详情失败");

        articleKeywordService.add(articleEntity.getId(), articleDto.getKeywords());
        ossFileService.setUse(articleEntity.getThumbnail());

        articleDto.setId(articleEntity.getId());
        return true;
    }

    /**
     * 修改
     *
     * @param articleDto
     * @return
     */
    @Override
    public Boolean edit(ArticleDTO articleDto) {
        //原数据
        ArticleDO oldArticleEntity = this.getById(articleDto.getId());
        ArticleContentVO oldContentVo = articleContentService.getInfo(articleDto.getId());

        //更新文章
        ArticleDO articleEntity = ArticleConverter.dtoToEntity(articleDto);
        if (!this.updateById(articleEntity)) return false;

        if (StrUtil.isNotBlank(oldArticleEntity.getVideo()) && StrUtil.isBlank(articleDto.getVideo())) {
            LambdaUpdateWrapper<ArticleDO>
                    updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ArticleDO::getId, articleDto.getId());
            updateWrapper.set(ArticleDO::getVideo, "");
            updateWrapper.set(ArticleDO::getVideoInfo, new VideoInfoDTO());
            update(updateWrapper);
        }

        //设置图片状态
        ossFileService.setDeleted(oldArticleEntity.getThumbnail());
        ossFileService.setDeleted(oldArticleEntity.getVideo());
        ossFileService.setUse(articleEntity.getThumbnail());
        ossFileService.setUse(articleEntity.getVideo());


        //更新详情
        ArticleContentDTO articleContentDTO = new ArticleContentDTO();
        articleContentDTO.setArticleId(articleEntity.getId());
        articleContentDTO.setContent(articleDto.getContent());
        if (!articleContentService.edit(articleContentDTO)) return false;

        //更新关键字
        articleKeywordService.add(articleEntity.getId(), articleDto.getKeywords());

        return true;
    }

    @Override
    public Boolean delete(Integer id) {
        ArticleDO oldArticleEntity = this.getById(id);
        ArticleContentVO oldContentVo = articleContentService.getInfo(id);

        if (!this.removeById(id)) return false;

        ossFileService.setDeleted(oldArticleEntity.getThumbnail());
        ossFileService.setDeleted(oldArticleEntity.getVideo());
        ossFileService.setDeleted(oldContentVo.getContent(), true);
        return true;
    }


    @Override
    public List<ArticleVO> setAppData(List<ArticleVO> articleList, UserVO userVO) {
        if (ObjectUtil.isEmpty(articleList)) return articleList;

        if (ObjectUtil.isNotNull(userVO) && ObjectUtil.isNotEmpty(userVO.getUid())) {
            List<Integer> ids = articleList.stream()
                    .map(ArticleVO::getId)
                    .collect(Collectors.toList());

            LambdaQueryWrapper<CollectDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CollectDO::getBizType, BizTypeEnum.CMS_ARTICLE.getCode());
            wrapper.in(CollectDO::getBizId, ids);
            wrapper.eq(CollectDO::getUid, userVO.getUid());
            wrapper.select(CollectDO::getBizId);

            List<CollectDO> collectList = collectService.list(wrapper);
            List<Integer> collectIds = collectList.stream()
                    .map(CollectDO::getBizId)
                    .collect(Collectors.toList());
            articleList.forEach(item -> {
                item.setCollect(collectIds.contains(item.getId()));
            });
        }

        if (!isVip(userVO)) {
            articleList.forEach(item -> {
                Integer minLength = Math.min(item.getSummary().length(), 40);
                String str = item.getSummary().substring(0, minLength) + "...\n";
                str += "**************************\n";
                str += "******VIP会员可见*******\n";
                str += "**************************";

                item.setSummary(str);
            });
        }

        return articleList;
    }

    private Boolean isVip(UserVO userVO) {
        if (ObjectUtil.isNull(userVO)) return false;
        if (ObjectUtil.isNotNull(userVO.getTryNum()) && userVO.getTryNum() > 0) return true;

        if (ObjectUtil.isEmpty(userVO.getVipGrade()) || userVO.getVipGrade() < 1) return false;

        if (userVO.getVipType().equals(VipTypeEnum.PERPETUAL.getCode())) {
            return true;
        } else if (userVO.getVipType().equals(VipTypeEnum.LIMITED.getCode())) {
            return userVO.getVipExpiredTime().isAfter(LocalDateTime.now());
        }

        return false;
    }
}
